package com.jkgj.skykingkong.tms.web;

import com.jkgj.skykingkong.tms.application.RbacService;
import com.jkgj.skykingkong.tms.application.command.CreateUserCommand;
import com.jkgj.skykingkong.tms.application.command.GrantRolesCommand;
import com.jkgj.skykingkong.tms.application.command.UpdateUserCommand;
import com.jkgj.skykingkong.tms.application.dto.UserInfo;
import com.jkgj.skykingkong.tms.application.query.UserQuery;
import com.jkgj.skykingkong.tms.domain.model.rbac.User;
import com.jkgj.skykingkong.tms.domain.model.rbac.UserRepository;
import com.jkgj.skykingkong.tms.infrastructure.util.mapper.BeanMapper;
import io.ebean.ExpressionList;
import io.ebean.PagedList;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.ebean.querychannel.EbeanQueryChannelService;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.security.Principal;
import java.util.Arrays;

/**
 * @author Xuegui Yuan
 */
@RestController
@RequestMapping("/users")
public class UserController {
  @Autowired
  private UserRepository userRepository;

  @Autowired
  private RbacService rbacService;

  @GetMapping("/me")
  public UserInfo getMe(Principal principal) {
    User user = userRepository.findUserByUsername(principal.getName());
    return BeanMapper.map(user, UserInfo.class);
  }

  @GetMapping
  public Page<UserInfo> list(Pageable pageable,
                             UserQuery userQuery) {
    ExpressionList<User> expressionList = EbeanQueryChannelService.query(User.class).where();
    if (StringUtils.isNoneBlank(userQuery.getKeyword())) {
      EbeanQueryChannelService.orContains(expressionList, Arrays.asList("username",
          "mobile",
          "email",
          "name"), userQuery.getKeyword());
    } else {
      EbeanQueryChannelService.containsIfNoneBlank(expressionList,
          "username",
          userQuery.getUsername());
      EbeanQueryChannelService.containsIfNoneBlank(expressionList,
          "mobile",
          userQuery.getMobile());
      EbeanQueryChannelService.containsIfNoneBlank(expressionList,
          "email",
          userQuery.getEmail());
      EbeanQueryChannelService.containsIfNoneBlank(expressionList,
          "name",
          userQuery.getName());
    }
    PagedList<User> pagedList = EbeanQueryChannelService.queryWithPage(expressionList, pageable.getPageNumber() , pageable.getPageSize())
    //PagedList<User> pagedList = EbeanQueryChannelService.queryWithPage(expressionList, pageable)
        .findPagedList();
    return new PageImpl<UserInfo>(BeanMapper.mapList(pagedList.getList(),
        User.class, UserInfo.class),
        pageable,
        pagedList.getTotalCount());
  }

  @GetMapping("/{id}")
  public ResponseEntity<UserInfo> get(@PathVariable Long id) {
    User user = userRepository.findOne(id);
    return ResponseEntity.ok(BeanMapper.map(user, UserInfo.class));
  }

  @PostMapping
  public ResponseEntity<?> create(@RequestBody CreateUserCommand createUserCommand) {
    rbacService.createUser(createUserCommand);
    return ResponseEntity.ok().build();
  }

  @PatchMapping("/{id}")
  public ResponseEntity<?> update(@PathVariable Long id,
                                  @RequestBody UpdateUserCommand updateUserCommand) {
    updateUserCommand.setId(id);
    rbacService.updateUser(updateUserCommand);
    return ResponseEntity.ok().build();
  }

  @DeleteMapping("/{id}")
  public ResponseEntity<?> delete(@PathVariable Long id) {
    rbacService.deleteUser(id);
    return ResponseEntity.noContent().build();
  }

  @PostMapping("/{id}/grant")
  @Transactional
  public ResponseEntity<?> grant(@PathVariable Long id, @RequestBody GrantRolesCommand grantRolesCommand) {
    rbacService.grantRoles(id, grantRolesCommand.getRoleCodes());
    return ResponseEntity.ok().build();
  }

  @PostMapping("/{id}/deny/{enable}")
  public ResponseEntity<?> deny(@PathVariable Long id, @PathVariable Boolean enable) {
    if (enable) {
      rbacService.enableUser(id);
    } else {
      rbacService.disableUser(id);
    }

    return ResponseEntity.ok().build();
  }
}
